/**
 * @brief AT指令处理模块。解析AT指令，调度AT指令
 * @version 1.0
 * @date 2018-2-27
 * @author 宋炜
*/

#ifndef AT_H
#define AT_H

#include <string>
#include <map>
#include <functional>
#include <atomic>
#include <tinyxml.h>
#include "sys_var.hpp"
#include "filterio.h"
#include "ary_str.hpp"
#include "timer.hpp"
#include "config.hpp"

#if defined( __USE_MEMPOOL__)
#   include<jemalloc/jemalloc.h>
#endif

class atInst : public filterIO
{
public:
    /// 串口at指令握手操作过程。
    ///上位机                                          模块
    ///  |                                               |
    ///  |            +++                                |
    ///  |---------------------------->----------->------|
    ///  |                              a                |
    ///  |--------<--------<-----------------------------|
    ///  |            a                                  |
    ///  |---------------------------->----------->------|
    ///  |                              ok               |
    ///  |-------<--------<------------------------------|

	struct status{
		enum value{
			TRANS,                             // 透传状态
			HANDSHAKEING,                      // 握手状态
			HANDSHAKEING_2,                    // 握手状态2
			AT                                 // AT指令状态
		};
	};

	/*
	* AT hash表格式定义
	*/
    	struct stAtHash{
		std::string   reg_str;      // 语法的正则表达式
		std::string   fun_desc;     // 功能描述
		std::string   err_msg;      // 错误信息提示
	/*
	* AT指令HASH表，通过AT指令的命令字检索AT指令。找到的对象就是实际的AT指令
	* 操作函数
	*    void fun( const std::string& at , const ArrayString params );
	*  at , 原始的AT指令
	*  param , 是AT指令的参数表。如果AT指令没有参数，则参数表内不需要提供任何
	*          参数，如果有提供参数，则会被忽略。
	* 操作的结果会根据情况生成AT指令的反馈字符串，然后调用backward反馈
	*/
    		std::function< void ( const std::string& , const ArrayString& )>  fun;
	// ///////////////////////////////////////////////////////////////////////////////////////////////
		stAtHash( );
		stAtHash( const std::string& reg_str , const std::string& fun_desc, const std::string& err_msg );
		stAtHash( const stAtHash& b );
		stAtHash( stAtHash && b );

		stAtHash& operator=( stAtHash&& b );
		stAtHash& operator=( const stAtHash& b );

		~stAtHash();

		operator bool();
    	};
	/// AT 指令散列表。散列表使用AT指令的名称进行检索AT指令，获得AT指令对象后然后调用其中的回调
	/// 函数执行AT指令的操作
	typedef std::map< std::string , struct stAtHash > 		atgHash_t;
	typedef typename atgHash_t::iterator                    atgHashIt_t;
	/*
	 * 定义AT指令引擎类型。AT指令引擎类型主要分成密码AT指令引擎和状态机AT指令引擎
     	 * 密码AT指令引擎主要用于网络AT指令和短信AT指令
	 */
	typedef bool 				at_type;
	const static at_type    		at_serial;
	const static at_type    		at_net;

	std::string             		AT_OK_STR;               // AT指令返回的OK字符串。
protected:
	bool                            m_at_type;               // 解析器类型
	atgHash_t                       m_at_hash;               // AT指令HASH表
	std::atomic<typename status::value>      m_status;       // AT 指令过滤器状态
	CTimer                          m_handshake_overtime;    // 串口AT指令握手超时时间

	std::atomic<bool>               m_echo;                  // 是否开启AT指令回显功能；true开启；false关闭

	err_code                        m_at_error;              // at 指令操作错误代码
	std::string                     m_at_pswd;               // AT 指令密码。如果引擎为密码引擎，则会比对AT指令密码，然后
    // 根据密码是否匹配执行AT指令
#if ENABLE_WIFI == 1 || ENABLE_PHY == 1
    	std::atomic< bool >             m_root_status;           // 是否运行在超级用户下
#endif
public:
	atInst( filterList *l , bool attype );
	virtual ~atInst();

	status::value Status()
	{
		return m_status.load();
	}
protected:
	/**
	 * @brief 初始化操作hash表
	 */
	void init_hash();
	/**
	 * @brief 相应回复操作
	 * @param echo ， 回显的AT指令
	 * @param res , 回馈的操作结果
	 */
	void response( const std::string& echo , const std::string& res );
	/**
	 * @brief 检查at指令结构是否合法
	 * @param at , 完整的AT指令，包含了参数和结束符号
	 * @param cmd , 指令部分，不包含参数和结束符号
	 * @return 合法则返回true，否则返回false
	 */
	bool check_inst( const std::string& at , const std::string& cmd , atgHashIt_t & it);
	/**
	 * @brief 检查AT指令是否存在
	 */
	bool is_supported( const std::string& at );
	/**
	 * @brief 检查AT指令语法
	 * @param at , 完整的AT指令，包含了参数和结束符号
	 * @param cmd , 指令部分，不包含参数和结束符号
	 */
	bool check_gramma( const std::string& at , const std::string& cmd , atgHashIt_t & it);
	/**
	 * @brief 将AT指令拆分成两个部分
	 * @param at, 完整的AT指令，包含了参数和结束符号
	 * @param cmd , 指令部分，不包含参数和结束符号
	 * @param params ， 经过解析后的参数列表。这个列表采用字符串数组的方式进行存储
	 * @return。如果AT指令解析的过程中没有发生错误则返回true，否则返回false
	 */
	bool split( const std::string& at , std::string& cmd , ArrayString& params );
	/**
	 * @brief 处理密码引擎的AT指令
	 * @param cmd
	 */
	void process_at_pswd( const std::string& cmd );
	/**
	 * @brief 处理网口AT指令
	 * @param cmd , 
	 */
	void process_at_serial( const std::string& cmd );
	/**
	 * @brief 真实处理AT指令
	 * @param cmd
	 * @param at
	 * @param params
	 */
	void real_process_at( const std::string& cmd , const std::string& at , const ArrayString& params );
	/**
	 * @brief 实际执行过滤处理的操作函数。在各种不同应用的过滤器中实现。
	 * @note 参数rd在函数内部分别，但是在forward或者backword中释放。
	 * @param len
	 * @param data
	 * @param err
	 */
	bool on_forward( size_t len , const char * date , err_code &err , size_t& rlen , char ** rd ) ;
	bool on_backward( size_t len , const char * data , err_code &err , size_t& rlen , char ** rd  ) ;
	/* 以下的函数用来初始化AT指令HASH表 */
	void init_at();                   // AT
	void init_h();                    // AT + H
	void init_z();                    // AT+Z
	void init_reboot();               // AT+REBOOT
	void init_e();                    // AT+E
	void init_entm();                 // AT+ENTM
	void init_wkmod();                // AT+WKMOD
	void init_cmdpw();                // AT+CMDPW
	void init_stmsg();                // AT+STMSG
	void init_csq();                  // AT+CSQ
	void init_rstim();                // AT+RSTIM
	void init_sysinfo();              // AT+SYSINFO
	void init_ver();                  // AT+VER
	void init_reld();
	void init_clear();
	void init_cfgtf();

	void init_sn();
	void init_iccid();
	void init_imei();

	void init_uart();
	void init_uartft();
	void init_uartfl();
	/**
	 * @brief 额外增加的串口打包方式设置AT指令。
	 *   AT+UARTPK[?] 读取打包方式
	 *   AT+UARTPK=LENGTH | MIX | TIME | STREAM , 设置打包方式
	 */
	void init_uartpk();
	void init_rfcen();

	void init_apn();
	void init_socka();
	void init_sockb();
	void init_sockc();
	void init_sockd();
	void init_sockaen();
	void init_sockben();
	void init_sockcen();
	void init_sockden();
	void init_sockasl();
	void init_sockbsl();
	void init_sockcsl();
	void init_sockdsl();
	void init_sockalk();
	void init_sockblk();
	void init_sockclk();
	void init_sockdlk();
	void init_shorato();
	void init_shorbto();
	void init_shorcto();
	void init_shordto();
	void init_sockato();
	void init_sockbto();
	void init_sockcto();
	void init_sockdto();
	void init_sockind();
	void init_sdpen();

	void init_regen();
	void init_regen_a();
	void init_regen_b();
	void init_regen_c();
	void init_regen_d();

	void init_regtp();
	void init_regtp_a();
	void init_regtp_b();
	void init_regtp_c();
	void init_regtp_d();

	void init_regsnd();
	void init_regsnd_a();
	void init_regsnd_b();
	void init_regsnd_c();
	void init_regsnd_d();

	void init_regdt();
	void init_regdt_a();
	void init_regdt_b();
	void init_regdt_c();
	void init_regdt_d();

	void init_reghex_en();
	void init_reghex_ena();
	void init_reghex_enb();
	void init_reghex_enc();
	void init_reghex_end();

	void init_cloud();

	void init_hearten();
	void init_hearten_a();
	void init_hearten_b();
	void init_hearten_c();
	void init_hearten_d();

	void init_heartdt();
	void init_heartdt_a();
	void init_heartdt_b();
	void init_heartdt_c();
	void init_heartdt_d();

	void init_heartsnd();
	void init_heartsnd_a();
	void init_heartsnd_b();
	void init_heartsnd_c();
	void init_heartsnd_d();

	void init_hearttm();
	void init_hearttm_a();
	void init_hearttm_b();
	void init_hearttm_c();
	void init_hearttm_d();

	void init_heart_hex();
	void init_heart_hexa();
	void init_heart_hexb();
	void init_heart_hexc();
	void init_heart_hexd();
	
	void init_htpen();
	void init_htptp();
	void init_htpurl();
	void init_htpsv();
	void init_htphd();
	void init_htpto();
	void init_htpflt();

	void init_smsend();
	void init_cismssend();
	//
	void init_hz();
	void init_reset();
	void init_sockadd();
	void init_sock();
	void init_sockdel();
	void init_ping();
	void init_ca();
	void init_cer();

	void init_mqttsvr();
	void init_mqttuser();
	void init_mqtttpc();
	void init_mqttsnd();
	void init_mqttunsub();

	void init_kd();
	void init_comd();
	void init_netd();
	void init_ssl();
	void init_htps();
	void init_crypto();
	void init_zip();
	void init_filter();
	void init_report();
	void init_rmset();
	void init_rmta();
	void init_save();
	void init_gpsen();
	void init_agps();
	void init_gpsfreq();
	void init_gpssv();
	void init_gpsdat();
	void init_gpsspeed();
	void init_fsnset();
	
	void init_upgrade();
	void init_uppswd();
	void init_autoreboot();
	#if ENABLE_WIFI == 1 
	void init_wifien();
	void init_wifi();
	void init_wificln();
	#endif
	#if ENABLE_PHY == 1 
	void init_phyen();
	#endif
#if ENABLE_WIFI == 1 || ENABLE_PHY == 1
	TiXmlElement * getIPNode( TiXmlElement * root );
	TiXmlElement * getStart( TiXmlElement * root );
	TiXmlElement * getStop( TiXmlElement * root );
	TiXmlElement * getMask( TiXmlElement * root );
	/**
	 * @brief 初始化试制LAN参数的AT指令.指定路由器地址，DHCP起始和中止，以及网络掩码
	 *   AT+LAN=ip,start , stop ,netmask
	 */
	void init_lan();

	/**
	 * @brief 调𢿄端口
	 */
	void firewall_filter_port( ArrayString& rst );
	/**
	 * @brief 过滤掉杂散内容，剩下路由表
	 */
	void firewall_out_filter_forward( ArrayString& rst );
	/**
	 * @brief 设置4G出站规则
	 * @param ip 设置路由目标IP地址
	 * @return
	 */
	std::string do_firewall_set( const std::string & ip );
	/**
	 * 是否开启防火墙
	 */
	void init_firewall();
	/**
	 * @brief 设置ROOT密码
	 */
	void init_rootPswd();
	/**
	 * @brief 设置或读取防火墙规则。只允许列表中的目的地址出站.
	 * 发送时的AT指令：
	 *    AT+FIRERUL 或 AT+FIRERUL? 查询出站规则，结果格式如下，如果有多个规则则分多行显示：
	 *      AT+FIRERUL
	 *      OK
	 *      +FIREURL:ALL,117.78.33.204,101
	 *               TCP,117.78.33.204,400
	 *   
	 */
	void init_firelist();
	/**
	 * @brief 设置或读取防火墙规则，只允许列表中的MAC设备访问
	 */
	void init_firemac();
	/**
	 * @brief 保存防火墙设置
	 */
	void init_firesave();
	
	/**
	 * @brief 读取MAC规则
	 * @param rst , MAC 列表
	 */
	void get_firewall_mac( ArrayString & rst );
	/**
	 * @brief 读取出站规则
	 * @param rst IP 地址列表
	 */
	void get_firewall_out( ArrayString& rst );
	/**
	 * @brief 设置LAN口参数
	 * @param ip
	 * @param start,
	 * @param stop,
	 * @param mask
	 */
	std::string set_lan_params( std::shared_ptr<CSysVar> ptvar ,
				const std::string& ip , const std::string& start , 
				const std::string& stop , const std::string& mask );
	void query_lan_params( std::shared_ptr<CSysVar> ptvar , std::string& rst );
	int update_mobileap_cfg(  const std::string& ip , 
				const std::string& start , 
				const std::string& end , 
				const std::string& mask );
#endif
#if ENABLE_MODBUS == 1 
	void init_modbus_en();
	void init_mbadd();
	void init_mbl();
	void init_mbdel();
#endif
	/**
	 * 真实的参数分割程序
	 */
	bool real_split( const std::string& at , const std::string& cmd , ArrayString& params );
	void bad_at_start();
};
extern bool IsInSerialAT();
extern bool IsATHandShake();
/*
* 短信AT指令的定义
*/
class atSMS : public atInst
{
public:
	atSMS(at_type type , filterList *l) : atInst( l , false ){}
	virtual ~atSMS(){};
};
/******************************************************************************************************
 * 串口AT指令的定义。 
 */
class atCom : public atInst
{
public:
	static atCom * ptSerialAT;
public:
    	atCom(at_type type , filterList *l) : atInst( l , true )
	{
		ptSerialAT = this;
	}
    	virtual ~atCom(){};
};
/******************************************************************************************************
 *  网络AT指令定义 
 */
class atNet : public atInst
{
public:
	atNet(at_type type , filterList *l) : atInst( l , false ){}
	virtual ~atNet(){};
};
#endif // AT_H
